package com.boruan.shengtangfeng.api.jwt.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import com.boruan.shengtangfeng.api.jwt.UserSubject;
import com.boruan.shengtangfeng.core.utils.CookieUtil;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtUtil {

	private static final String CLAIM_KEY_USER_ID = "uid";
	private static final String CLAIM_KEY_USER_OPENID = "openId";
	private static final String CLAIM_KEY_USER_ICON = "icon";
	private static final String CLAIM_KEY_USER_MOBILE = "sub";
	private static final String CLAIM_KEY_USER_NAME = "name";
	private static final String CLAIM_KEY_CREATED = "created";

	@Value("${jwt.secret}")
	private String secret; // 秘钥

	@Value("${jwt.expiration}")
	private Long expiration; // 过期时间

	@Value("${jwt.header}")
	private String tokenHeader;

	@Value("${jwt.tokenHead}")
	private String tokenHead;

	@Value("${jwt.tokenParam}")
	private String tokenParam;

	/**
	 * 从请求中获取token
	 * 
	 * @param HttpServletRequest
	 * @return
	 */
	public String getToken(HttpServletRequest request) {
		String authHeader = request.getHeader(this.tokenHeader);
		if (authHeader != null && authHeader.startsWith(tokenHead)) {
			final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
			return authToken;
		}
		authHeader = request.getParameter(tokenParam);
		if (authHeader != null && authHeader.startsWith(tokenHead)) {
			final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
			return authToken;
		}
		authHeader = CookieUtil.readLoginToken(request);
		if (authHeader != null && authHeader.startsWith(tokenHead)) {
			final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
			return authToken;
		}
		return null;
	}

	/**
	 * 从token中获取用户openId
	 * 
	 * @param token
	 * @return
	 */
	public String getOpenIdFromToken(String token) {
		String openId;
		try {
			final Claims claims = getClaimsFromToken(token);
			openId = claims.getSubject();
		} catch (Exception e) {
			openId = null;
		}
		return openId;
	}

	/**
	 * 从token中获取用户account
	 * 
	 * @param token
	 * @return
	 */
	public String getUserAccountFromToken(String token) {
		String useraccount;
		try {
			final Claims claims = getClaimsFromToken(token);
			useraccount = claims.getSubject();
		} catch (Exception e) {
			useraccount = null;
		}
		return useraccount;
	}

	/**
	 * 从token中获取用户JwtUser
	 * 
	 * @param token
	 * @return
	 */
	public UserSubject getJwtUserFromToken(String token) {
		UserSubject jwtUser = null;
		try {
			final Claims claims = getClaimsFromToken(token);
			String mobile = claims.getSubject();
			String userName = claims.get(CLAIM_KEY_USER_NAME, String.class);
			String openId = claims.get(CLAIM_KEY_USER_OPENID, String.class);
			String icon = claims.get(CLAIM_KEY_USER_ICON, String.class);
			Long userId = claims.get(CLAIM_KEY_USER_ID, Long.class);
			ArrayList<GrantedAuthority> authorities = new ArrayList<>();
			jwtUser = new UserSubject(userId, mobile, userName, "", openId, "", icon, authorities);

		} catch (Exception e) {
		}
		return jwtUser;
	}
	/**
	 * 从token中获取用户JwtUser
	 * 
	 * @param token
	 * @return
	 */
	public Long getUserIdFromToken(String token) {
	    try {
	        final Claims claims = getClaimsFromToken(token);
	        Long userId = claims.get(CLAIM_KEY_USER_ID, Long.class);
	        return userId;
	    } catch (Exception e) {
	        return null;
	    }
	}

	/**
	 * 获取当前用户JwtUser，没登录返回NULL
	 * 
	 * @return
	 */
	public static UserSubject getCurrentJwtUser() {
	    Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
	    if(authentication==null) {
	        return null;
	    }
		UserSubject user = (UserSubject) authentication.getPrincipal();
		return user;
	}

	/**
	 * 从token中获取创建时间
	 * 
	 * @param token
	 * @return
	 */
	public Date getCreatedDateFromToken(String token) {
		Date created;
		try {
			final Claims claims = getClaimsFromToken(token);
			created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
		} catch (Exception e) {
			created = null;
		}
		return created;
	}

	/**
	 * 获取token的过期时间
	 * 
	 * @param token
	 * @return
	 */
	public Date getExpirationDateFromToken(String token) {
		Date expiration;
		try {
			final Claims claims = getClaimsFromToken(token);
			expiration = claims.getExpiration();
		} catch (Exception e) {
			expiration = null;
		}
		return expiration;
	}

	/**
	 * 获取token的过期时间
	 * 
	 * @param token
	 * @return
	 */
	public Date getExpirationDateFromToken(HttpServletRequest request) {
		final String token = getToken(request);
		Date expiration;
		try {
			final Claims claims = getClaimsFromToken(token);
			expiration = claims.getExpiration();
		} catch (Exception e) {
			expiration = null;
		}
		return expiration;
	}

	/**
	 * 从token中获取claims
	 * 
	 * @param token
	 * @return
	 */
	private Claims getClaimsFromToken(String token) {
		Claims claims;
		try {
			claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
		} catch (Exception e) {
			claims = null;
		}
		return claims;
	}

	/**
	 * 生存token的过期时间
	 * 
	 * @return
	 */
	private Date generateExpirationDate() {
		return new Date(System.currentTimeMillis() + expiration * 1000);
	}

	/**
	 * 判断token是否过期
	 * 
	 * @param token
	 * @return
	 */
	private Boolean isTokenExpired(String token) {
		final Date expiration = getExpirationDateFromToken(token);
		Boolean result = expiration.before(new Date());
		return result;
	}

	/**
	 * 生成token
	 * 
	 * @param userDetails
	 * @return
	 */
	public String generateToken(Long uid, String mobile, String userName, String openId, String userIcon) {
		Map<String, Object> claims = new HashMap<>();
		claims.put(CLAIM_KEY_USER_OPENID, openId);
		claims.put(CLAIM_KEY_USER_MOBILE, mobile);
		claims.put(CLAIM_KEY_USER_NAME, userName);
		claims.put(CLAIM_KEY_CREATED, new Date());
		claims.put(CLAIM_KEY_USER_ID, uid);
		claims.put(CLAIM_KEY_USER_ICON, userIcon);
		return generateToken(claims);
	}

	private String generateToken(Map<String, Object> claims) {
		return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate())
				.signWith(SignatureAlgorithm.HS512, secret).compact();
	}

	/**
	 * token 是否可刷新
	 * 
	 * @param token
	 * @return
	 */
	public Boolean canTokenBeRefreshed(String token) {
		final Date created = getCreatedDateFromToken(token);
		return !isTokenExpired(token);
	}

	/**
	 * 刷新token
	 * 
	 * @param token
	 * @return
	 */
	public String refreshToken(String token) {
		String refreshedToken;
		try {
			final Claims claims = getClaimsFromToken(token);
			claims.put(CLAIM_KEY_CREATED, new Date());
			refreshedToken = generateToken(claims);
		} catch (Exception e) {
			refreshedToken = null;
		}
		return refreshedToken;
	}

	/**
	 * 验证token
	 * 
	 * @param token
	 * @param userDetails
	 * @return
	 */
	public Boolean validateToken(String token) {
		Boolean result = (!isTokenExpired(token));
		return result;
	}
}
